Skip to content

feat(android): [Unhandled Sessions 3] Add internal non-terminating envelope capture - #5921

Open
buenaflor wants to merge 15 commits into
feat/unhandled-sessions-cachefrom
feat/unhandled-sessions-internal-api
Open

feat(android): [Unhandled Sessions 3] Add internal non-terminating envelope capture#5921
buenaflor wants to merge 15 commits into
feat/unhandled-sessions-cachefrom
feat/unhandled-sessions-internal-api

Conversation

@buenaflor

@buenaflor buenaflor commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

PR Stack (Unhandled Sessions)


📜 Description

Adds InternalSentrySdk.captureEnvelopeNonTerminating(byte[]) for hybrid runtimes where an unhandled exception does not terminate the process.

Unlike captureEnvelope(byte[], boolean), it does not treat handled=false as a crash. Instead it:

  • flags the current session and increments its error count,
  • keeps the session Ok with the same session id on the scope,
  • attaches no session item and starts no new session,
  • persists the session so the flag survives process death.

The session is finalized later by normal lifecycle (endSession, background, or previous-session recovery) as unhandled, unless a native crash escalates it to crashed. captureEnvelope(byte[], boolean) is unchanged.

Also in this PR:

  • Scope.IWithSession becomes public so InternalSentrySdk can mutate the session under the scope lock; it is the only consumer. It carries @ApiStatus.Internal like IWithTransaction and IWithPropagationContext, so it is not supported API despite being public.
  • A shared eventStateOf returning EnvelopeEventState, replacing two loops that computed the same booleans by different routes, plus a shared readEnvelope.
  • The code added here catches Exception rather than Throwable, so OutOfMemoryError and friends propagate instead of being swallowed. The existing captureEnvelope keeps its catch (Throwable).

💡 Motivation and Context

Flutter forwards handled=false events through the terminating hybrid capture path. That marks the session crashed and may start a replacement session even though the Flutter process keeps running, incorrectly lowering crash-free session rates.

💚 How did you test it?

New InternalSentrySdkTest coverage: the session staying Ok with the same id and the flag persisted to disk; endSession afterwards finalizing as unhandled; and a later hard crash finalizing the old session as crashed and starting a fresh Ok session. Existing captureEnvelope tests confirm that path is unchanged.

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.

🔮 Next steps

Update the Flutter Android bridge to use captureEnvelopeNonTerminating for non-terminating unhandled events.

⚠️ Merge this PR using a merge commit (not squash). Only the collection branch is squash-merged into main.

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor
Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 24da0ef

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@sentry

sentry Bot commented Aug 10, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.53.0 (1) release

⚙️ sentry-android Build Distribution Settings

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 314.62 ms 364.48 ms 49.86 ms
Size 0 B 0 B 0 B

Previous results on branch: feat/unhandled-sessions-internal-api

Startup times

Revision Plain With Sentry Diff
075631e 355.90 ms 458.42 ms 102.52 ms
c2189fd 300.61 ms 362.84 ms 62.22 ms
f4f202f 315.94 ms 369.24 ms 53.30 ms
8014a1f 304.46 ms 376.38 ms 71.92 ms
211ab30 314.79 ms 389.47 ms 74.68 ms
bc96797 321.86 ms 377.38 ms 55.52 ms
ed254d0 331.02 ms 359.08 ms 28.06 ms
b696cfd 320.00 ms 358.66 ms 38.66 ms
4f9af8d 329.51 ms 342.60 ms 13.09 ms
0650636 387.86 ms 457.88 ms 70.02 ms

App size

Revision Plain With Sentry Diff
075631e 0 B 0 B 0 B
c2189fd 0 B 0 B 0 B
f4f202f 0 B 0 B 0 B
8014a1f 0 B 0 B 0 B
211ab30 0 B 0 B 0 B
bc96797 0 B 0 B 0 B
ed254d0 0 B 0 B 0 B
b696cfd 0 B 0 B 0 B
4f9af8d 0 B 0 B 0 B
0650636 0 B 0 B 0 B

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

6 similar comments
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@buenaflor
buenaflor force-pushed the feat/unhandled-sessions-internal-api branch from 56ab999 to 1906ec6 Compare August 11, 2026 10:00
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

2 similar comments
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@buenaflor
buenaflor force-pushed the feat/unhandled-sessions-internal-api branch from 06f5823 to ae23921 Compare August 11, 2026 11:53
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@buenaflor
buenaflor force-pushed the feat/unhandled-sessions-internal-api branch from ae23921 to b2ff9d9 Compare August 11, 2026 11:54
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@buenaflor
buenaflor force-pushed the feat/unhandled-sessions-internal-api branch from b2ff9d9 to 945602b Compare August 11, 2026 11:59
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

buenaflor and others added 7 commits August 12, 2026 10:10
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…thods

Both methods scanned the envelope's events to derive the same pair of
booleans, but wrote it differently - one via isCrashed(), the other via
getUnhandledException() != null, which is the same predicate. Extract a
single scanEvents returning NONE/ERRORED/UNHANDLED so the two agree by
construction and an unhandled-but-not-errored state is unrepresentable.

Co-authored-by: Cursor <cursoragent@cursor.com>
The annotation had no mechanical effect: apiValidation configures only
ignoredPackages/ignoredProjects and no nonPublicMarkers, so the type is
tracked in sentry.api either way. Regenerating the dump after removing
it produces no diff.

The interface still has to be public, since the lambda in
InternalSentrySdk.captureEnvelopeNonTerminating targets it from
io.sentry.android.core.

Co-authored-by: Cursor <cursoragent@cursor.com>
Both the method and the enum were plural nouns that read as if they
returned the envelope's events, when they return a single summary value.
That made "events != EnvelopeEvents.NONE" look like an emptiness check
rather than "nothing worth recording happened". EnvelopeEventState also
lines up with the Session.State vocabulary already used here.

Co-authored-by: Cursor <cursoragent@cursor.com>
Same reasoning as the cache change: this catch predates the feature, and
narrowing it changed how an Error during capture behaves for every
existing caller while leaving the file's three other catch (Throwable)
blocks untouched. captureEnvelopeNonTerminating and readEnvelope are new
code and keep catch (Exception).

Co-authored-by: Cursor <cursoragent@cursor.com>
@buenaflor
buenaflor force-pushed the feat/unhandled-sessions-internal-api branch from 5a16f9b to b01be8a Compare August 12, 2026 08:11
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@buenaflor
buenaflor marked this pull request as ready for review August 12, 2026 11:56
Copilot AI lite review requested due to automatic review settings August 12, 2026 11:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new internal capture path for hybrid Android runtimes (e.g. Flutter) to report handled=false events that don’t terminate the process, ensuring the active session remains Ok (same SID) while recording a non-terminating unhandled error that will later finalize as unhandled via normal lifecycle/persistence flows.

Changes:

  • Add InternalSentrySdk.captureEnvelopeNonTerminating(byte[]) that flags/persists the current session without attaching a session item or starting a new session.
  • Expose Scope.IWithSession so Android-core code can mutate session state under the scope lock; update API dumps accordingly.
  • Add Android-core tests for the new non-terminating behavior and persist-to-disk semantics; add Truth as a test dependency; add changelog entry.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
sentry/src/main/java/io/sentry/Scope.java Makes IWithSession public to enable session mutation under the scope lock from other modules.
sentry/api/sentry.api API dump updated to include the now-public Scope.IWithSession.
sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java Adds captureEnvelopeNonTerminating, plus shared envelope read/event scanning helpers and session persistence hook.
sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt Adds unit tests validating non-terminating unhandled behavior (session stays Ok, flag persisted, later finalization).
sentry-android-core/build.gradle.kts Adds Google Truth as a test dependency for new assertions.
sentry-android-core/api/sentry-android-core.api API dump updated for new InternalSentrySdk.captureEnvelopeNonTerminating.
CHANGELOG.md Adds an Unreleased “Internal” entry documenting the new internal hybrid capture API.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread sentry/src/main/java/io/sentry/Scope.java
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

Matches IWithTransaction and IWithPropagationContext. The interface has to
be public for InternalSentrySdk to use it, but it is not supported API.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants